home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / GX Libraries / FontMenuLibrary.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-27  |  23.4 KB  |  753 lines  |  [TEXT/MPS ]

  1.  
  2. /*
  3.     File:        FontMenuLibrary.c
  4.  
  5.     Contains:    graphics libraries - gxFont menu library routines
  6.  
  7.     Written by:    Cary Clark, Georgiann Delaney, Michael Fairman, Dave Good, Robert Johnson, Keith McGreggor, Mike Reed, Oliver Steele, David Van Brink, Chris Yerga
  8.  
  9.     Copyright:    © 1995 by Apple Computer, Inc., all rights reserved.
  10.  
  11.     Change History (most recent first):
  12.  
  13.          <6>     6/26/95    TD        remove local copy of FlipBack
  14.          <5>      5/4/95    JD        updating DelMenuItem to DeleteMenuItem
  15.          <4>      4/7/95    jtd        taking out all references to 'GestaltEqu.h'
  16.          <3>     1/24/95    JD        updated to latest GX 1.1 source (as of 16 Jan 1995)
  17.          <2>      1/9/95    JD        changed 'boolean' to 'Boolean'
  18.          <1>      1/9/95    JD        First checked in.
  19. */
  20.  
  21. #include <Resources.h>
  22. #include <Menus.h>
  23. #include <Memory.h>
  24. #include <ToolUtils.h>
  25. #include <Types.h>
  26. #include <Fonts.h>
  27. #include <Menus.h>
  28. #include <Gestalt.h>
  29. #include <GXTypes.h>
  30. #include <GXEnvironment.h>
  31. #include <GXGraphics.h>
  32. #include <GXLayout.h>
  33. #include <GXFonts.h>
  34. #include "FontMenuLibrary.h"
  35. #include "FontLibrary.h"
  36. #include "LayoutFeatureConstants.h"
  37.  
  38. /* jtdfix - what are we doing here?? */
  39. #if !defined(__powerc)
  40.     pascal Handle XGetNextFOND(Handle fontHandle) = {0x700A, 0xA822}; /* this disappeared in the latest release of THINK C */
  41. #else
  42.     #define XGetNextFOND GetNextFOND
  43. #endif
  44.  
  45. /*****************************************
  46.  *  Menu manager library routines to handle fonts *
  47.  *****************************************/
  48.  
  49. void DeleteMenuItems(MenuHandle menuH)
  50. {
  51.     int i;
  52.  
  53.     for (i = CountMenuItems(menuH); i > 0; --i)
  54.         DeleteMenuItem(menuH, i);
  55. }
  56.  
  57. static long AppendMenuName(MenuHandle menu, long length, unsigned char name[])
  58. {
  59.     name[0] = length < 255 ? length : 255;
  60.     AppendMenu(menu, (const unsigned char *) "\pfont name");  /*** some full names disable the item */ /* cast for Think C 4.0 */
  61.     SetMenuItemText(menu, CountMenuItems(menu), name);
  62.     return length > 255;
  63. }
  64.  
  65. static MenuHandle NewMenuName(short menuID, long length, unsigned char *title)
  66. {
  67.     Str255 str;
  68.  
  69.     str[0] = length < 255 ? length : 255;
  70.     BlockMove(title+1, &str[1], str[0]);
  71.     return NewMenu(menuID, str);
  72. }
  73.  
  74. static int Str255Compare(Str255 a, Str255 b)
  75. {
  76.     int i, minSize = a[0] < b[0] ? a[0] : b[0];
  77.  
  78.     for (i = 1; i < minSize; i++) {
  79.         if (a[i] == b[i])
  80.             continue;
  81.         return a[i] - b[i];
  82.     }
  83.     return a[0] - b[0];
  84. }
  85.  
  86. /*
  87. *       sorts the text, command char, and item mark 
  88. *       this way any submenus will sort with the  item     
  89.  *  THIS SHOULD CALL SOME COOL INTL. SORT ROUTINE
  90.  */
  91. void SortMenu(MenuHandle menu)
  92. {
  93.     short i, j, count = CountMenuItems(menu);
  94.     
  95.     for (i = 2; i <= count; i++)
  96.         for (j = count; j >= i; --j) {
  97.             short lowercmdChar, uppercmdChar;
  98.             short lowermarkChar, uppermarkChar;
  99.             Str255 lower, upper;
  100.             GetMenuItemText(menu, j, lower);
  101.             GetMenuItemText(menu, j-1, upper);
  102.             GetItemCmd ( menu, j, &lowercmdChar );
  103.             GetItemCmd ( menu, j-1, &uppercmdChar );
  104.             GetItemMark ( menu, j, &lowermarkChar );
  105.             GetItemMark ( menu, j-1, &uppermarkChar );
  106.             
  107.             if (Str255Compare(lower, upper) < 0) {
  108.                 SetMenuItemText(menu, j, upper);
  109.                 SetMenuItemText(menu, j-1, lower);
  110.                 SetItemCmd ( menu, j, uppercmdChar );
  111.                 SetItemCmd ( menu, j-1, lowercmdChar );
  112.                 SetItemMark ( menu, j, uppermarkChar );
  113.                 SetItemMark ( menu, j-1, lowermarkChar );
  114.             }
  115.         }
  116. }
  117.  
  118. /*
  119.  *  Append a menu with the fonts' full names
  120.  */
  121. long FontMenu(MenuHandle menu)
  122. {
  123.     return FontPlatformMenu(menu, gxNoPlatform, gxNoScript, gxNoLanguage);
  124. }
  125.  
  126. /*
  127.  *  Append a menu with the fonts' full names for fonts that support the specified platform
  128.  */
  129. long FontPlatformMenu(MenuHandle menu, gxFontPlatform platform, gxFontScript script, gxFontLanguage language)
  130. {
  131.     gxFont* fonts;
  132.     long i, count, nameIndex;
  133.     
  134.     count = GXFindFonts(nil, 0, platform, script, language, 0, nil, 1, gxSelectToEnd, 0);
  135.     fonts = (gxFont*)NewPtr(count * sizeof(gxFont));
  136.     GXFindFonts(nil, 0, platform, script, language, 0, nil, 1, count, fonts);
  137.  
  138.     for (i = 0; i < count; i++)
  139.     {   unsigned char *name; 
  140.         long length;
  141.          
  142.         if ((length = GXFindFontName(fonts[i], gxFullFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, &nameIndex)) > 0) {
  143.             name = (unsigned char *) NewPtr(length + 1);
  144.             GXGetFontName(fonts[i], nameIndex, nil, nil, nil, nil, &name[1]);
  145.             AppendMenuName(menu, length, name);
  146.             DisposePtr((Ptr) name);
  147.         } 
  148.     }
  149.     DisposePtr((Ptr)fonts);
  150.     SortMenu(menu);
  151.     return count;
  152. }
  153.  
  154. /*
  155.  *  Append a menu with the fonts' family names
  156.  */
  157. long FontFamilyMenu(MenuHandle menu)
  158. {
  159.     return FontFamilyPlatformMenu(menu, gxNoPlatform, gxNoScript, gxNoLanguage);
  160. }
  161.  
  162. long FontFamilyPlatformMenu(MenuHandle menu, gxFontPlatform platform, gxFontScript script, gxFontLanguage language)
  163. {
  164.     gxFont* fonts;
  165.     long i, count;
  166.     
  167.     count = GXFindFonts(nil, gxFamilyFontName, platform, script, language, 0, nil, 1, gxSelectToEnd, nil);
  168.     fonts = (gxFont*)NewPtr(count * sizeof(gxFont));
  169.     GXFindFonts(nil, gxFamilyFontName, platform, script, language, 0, nil, 1, count, fonts);
  170.  
  171.     for (i = 0; i < count; i++)
  172.     {    unsigned char name[256];
  173.         
  174.             name[0] = GXFindFontName(fonts[i], gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  175.         if (name[0])
  176.             AppendMenuName(menu, name[0], name);
  177.     }
  178.     DisposePtr((Ptr)fonts);
  179.     SortMenu(menu);
  180.     return count;
  181. }
  182.  
  183. /*
  184.  *  Create a menu with the given gxFont family's name, filled with the styles available in that family
  185.  */
  186. MenuHandle FontStyleMenu(short menuID, gxFont family)
  187. {
  188.     long i, count = CountFontStyles(family);
  189.     long length;
  190.     MenuHandle menu;
  191.     unsigned char *name;
  192.  
  193.     if ((length = GXFindFontName(family, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil)) > 0) {
  194.         name = (unsigned char *) NewPtr(length + 1);
  195.         GXFindFontName(family, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  196.         menu = NewMenuName(menuID, length, name);
  197.         DisposePtr((Ptr) name);
  198.     } else
  199.         menu = NewMenu(menuID, (unsigned char *) "\pNo family name");    /* cast for Think C 4.0 */
  200.  
  201.     for (i = 1; i <= count; i++) {
  202.         gxFont sfnt = FindFontStyle(family, i, 0, 0, 0, 0, nil);
  203.         if ((length = GXFindFontName(sfnt, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil)) > 0) {
  204.             name = (unsigned char *) NewPtr(length + 1);
  205.             GXFindFontName(sfnt, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  206.             AppendMenuName(menu, length, name);
  207.             DisposePtr((Ptr)name);
  208.         }
  209.     }
  210.     SortMenu(menu);
  211.  
  212.     return menu;
  213. }
  214.  
  215. /*********************************************/
  216. /*                  HierFontMenu                        */
  217. /*                                                  */
  218. /*          the firstHierMenuID let's the application decide        */
  219. /*          what number the heir menu IDs start                     */ 
  220. /*                                                  */
  221. /*********************************************/
  222. short HierFontMenu(MenuHandle theMenu, short firstHierMenuID, fontFilterProc proc, fontMenuAttribute attr)
  223. {
  224.     long        i, count;
  225.     short    heirsUsed = 0;
  226.     long        howManyInstances;
  227.     long        howManyVariations;
  228.     gxFontVariation        *variations;
  229.     gxFontName        fontNameID;
  230.  
  231.     count = GXFindFonts(nil, 0, 0, 0, 0, 0, nil, 1, gxSelectToEnd, 0);
  232.     for (i = 1; i <= count; i++)
  233.     {    gxFont fontID;
  234.         long length;
  235.  
  236.         GXFindFonts(nil, 0, 0, 0, 0, 0, nil, i, 1, &fontID);
  237.         if (proc && !proc(fontID))
  238.             continue;
  239.         length = GXFindFontName(fontID, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil);
  240.         if (length)
  241.         {
  242.             unsigned char *name;
  243.             Boolean alreadyInMenu = false;
  244.             short numMItem;
  245.             short k;
  246.  
  247.             name = (unsigned char *) NewPtr(length + 1);
  248.             GXFindFontName(fontID, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  249.             numMItem = CountMenuItems(theMenu);/*how many items have i already added to the menu*/
  250.             for (k=1; k<= numMItem; k++)    /*check to see if the name is already in the menu*/
  251.             {
  252.                 Str255      str;
  253.  
  254.                 GetMenuItemText (theMenu, k, str);
  255.                 name[0] = length; /*fake str255*/
  256.                 if ( !Str255Compare(str, name) ) 
  257.                     alreadyInMenu = true;
  258.             }
  259.             if (!alreadyInMenu)         /*if not then add it*/
  260.             {
  261.                 MenuHandle hMenu;
  262.  
  263.                 AppendMenuName(theMenu, length, name);
  264.                 hMenu = FontStyleMenu(heirsUsed + firstHierMenuID, fontID);
  265.                 howManyInstances = (attr & noInstancesFontMenu) ? 0 : GXCountFontInstances(fontID);
  266.                 if( ( (CountMenuItems(hMenu)) > 1) || (howManyInstances > 0) )/*only add it if it is more than one item*/
  267.                 {   
  268.                     InsertMenu (hMenu, -1);
  269.                     
  270.                     SetItemCmd(theMenu, numMItem+1, hMenuCmd);
  271.                     SetItemMark(theMenu, numMItem+1, heirsUsed + firstHierMenuID);
  272.                     heirsUsed ++;
  273.                 }
  274.                 
  275.                 if(howManyInstances)
  276.                 {
  277.                     short m;
  278.                     
  279.                     howManyVariations = GXCountFontVariations(fontID);
  280.                     variations = (gxFontVariation*)NewPtr(sizeof(gxFontVariation) * howManyVariations);
  281.                     
  282.                     AppendMenu(hMenu, (const unsigned char *) "\p(-" );    /*dotted gxLine*/
  283.                     for(m = 1; m<=howManyInstances; m++)
  284.                     {
  285.                         DisposePtr((Ptr) name);
  286.                         fontNameID = GXGetFontInstance(fontID, m, variations);
  287.                         if ((length = GXFindFontName(fontID, fontNameID, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil)) > 0) 
  288.                         {
  289.                             name = (unsigned char *) NewPtr(length+1);
  290.                             GXFindFontName(fontID, fontNameID, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  291.                             AppendMenuName(hMenu, length, name);
  292.                         }
  293.                     }
  294.                 }
  295.             }
  296.             DisposePtr((Ptr) name);
  297.         } 
  298.     }
  299.     SortMenu(theMenu);
  300.     return(heirsUsed);
  301. }
  302.  
  303.  
  304. gxFont DoHierFontMenuCommand(long menuResult, short hierFontMenuID, long *instanceIndex)
  305. {
  306.     short    theItem = LoWord (menuResult);
  307.     short    theMenuID = HiWord (menuResult);
  308.     gxFont    fontID = nil;
  309.     Str255    str;
  310.  
  311.     *instanceIndex = 0;
  312.  
  313.     if (theMenuID == hierFontMenuID)
  314.     {    GetMenuItemText(GetMenuHandle(theMenuID), theItem, str);
  315.         GXFindFonts(nil, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, str[0], str+1, 1,1, &fontID);
  316.         if (GXFindFonts(fontID, gxFamilyFontName, gxNoPlatform, gxNoScript, gxNoLanguage, 0, nil, 1, gxSelectToEnd, nil) > 1)
  317.             GXFindFonts(fontID, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, 7, (unsigned char*)"Regular", 1,1, &fontID);
  318.     }
  319.     else if ((theMenuID > 0) && (theMenuID < 235))        /* range of hierarchial submenus && assume owner is hierfontMenuID */
  320.     {    MenuHandle  mh;
  321.         long    index;
  322.  
  323.         mh = GetMenuHandle(theMenuID);
  324.         BlockMove ( (**mh).menuData, str, (**mh).menuData[0]+1 );   /*the title of gxStyle menu is the family name*/
  325.         GXFindFonts(nil, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, str[0], str+1, 1,1, &fontID);
  326.  
  327.         index = theItem - (CountMenuItems( mh ) - GXCountFontInstances(fontID)) ;
  328.         if (index > 0)    /*it's an instance*/
  329.             *instanceIndex = index;
  330.         else
  331.         {    GetMenuItemText(mh, theItem, str);
  332.             GXFindFonts(fontID, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, str[0], str+1, 1,1, &fontID);
  333.         }
  334.     }   
  335.     HiliteMenu (0);
  336.     return fontID;
  337. }
  338.  
  339. Boolean DoHierFontMenuCommandStyle(long menuResult, short hierFontMenuID, gxStyle aStyle, long matchInfo)
  340. {
  341.     short    theItem = LoWord (menuResult);
  342.     short    theMenuID = HiWord (menuResult);
  343.     gxFont    sfnt;
  344.     Boolean    success = true;
  345.     long        instanceIndex;
  346.  
  347.     if (sfnt = DoHierFontMenuCommand(menuResult,  hierFontMenuID,  &instanceIndex))
  348.     {    if (matchInfo && ((theMenuID == hierFontMenuID) || (theItem == 0)))        /*theItem was on the family name*/
  349.             SetMatchingStyle(sfnt, aStyle, matchInfo);
  350.         else                    /*no gxStyle matching*/
  351.         {    GXSetStyleFont(aStyle, sfnt);
  352.             if (instanceIndex)
  353.             {    long                howManyVariations;
  354.                 gxFontVariation*    variations;
  355.                 
  356.                 howManyVariations = GXCountFontVariations(sfnt); 
  357.                 variations = (gxFontVariation*)NewPtr(sizeof(gxFontVariation) * howManyVariations);
  358.                 if (variations == nil)
  359.                     goto FAILURE;
  360.                 GXGetFontInstance(sfnt, instanceIndex, variations);
  361.                 GXSetStyleFont(aStyle, sfnt);
  362.                 GXSetStyleFontVariations(aStyle, howManyVariations, variations);
  363.                 DisposePtr((Ptr)variations);
  364.             }
  365.             else
  366.                 GXSetStyleFontVariations(aStyle, 0, nil);
  367.         }
  368.     }
  369.     else    /*not our menu*/
  370. FAILURE:
  371.         success = false;
  372.  
  373.     HiliteMenu (0);
  374.     return(success);
  375. }
  376.  
  377. short DoHierFontMenuCommandShape(long menuResult, short hierFontMenuID,gxShape aShape)
  378. {
  379.     short   theItem = LoWord (menuResult);
  380.     short   theMenuID = HiWord (menuResult);
  381.     gxFont        sfnt;
  382.     short   success = true;
  383.     long        instanceIndex;
  384.  
  385.     sfnt = DoHierFontMenuCommand(menuResult,  hierFontMenuID,  &instanceIndex);
  386.     if (sfnt)
  387.     {
  388.         GXSetShapeFont(aShape, sfnt);
  389.         if(instanceIndex)
  390.         {
  391.             long            howManyVariations;
  392.             gxFontVariation   *variations;
  393.         
  394.             howManyVariations = GXCountFontVariations(sfnt); 
  395.             variations = (gxFontVariation*)NewPtr(sizeof(gxFontVariation) * howManyVariations);
  396.             GXGetFontInstance(sfnt, instanceIndex, variations);
  397.             GXSetShapeFont(aShape, sfnt);
  398.             GXSetShapeFontVariations(aShape, howManyVariations, variations);
  399.             DisposePtr((Ptr)variations);
  400.         }
  401.         else
  402.             GXSetShapeFontVariations(aShape, 0, nil);
  403.     }
  404.     else    /*not our menu*/
  405.         success = false;
  406.     
  407.     HiliteMenu (0);
  408.     return(success);
  409. }
  410.  
  411. long FontToQD(gxFont fontID, long* styleBits)
  412. {
  413.     short resID, i, count;
  414.     OSType resType;
  415.     Str255 resName;
  416.     Handle sfnt;
  417.  
  418.     if (GXGetFont(fontID, (gxFontStorageReference*)&sfnt, nil) != gxResourceFontStorage)
  419.         goto NOT_FOUND;
  420.     GetResInfo(sfnt, &resID, &resType, resName);
  421.     if (ResError())
  422.         goto NOT_FOUND;
  423.  
  424.     count = CountResources('FOND');
  425.     for (i = 1; i <= count; i++)
  426.     {   Handle fond = GetIndResource('FOND', i);
  427.  
  428.         if (!ResError() && fond && *fond)
  429.             do
  430.             {   short* sp = (short*)(*fond + sizeof(FamRec));
  431.                 int entries = *sp++;
  432.                 
  433.                 for (; entries >= 0; --entries)
  434.                 {   if (*sp == 0 && sp[2] == resID)
  435.                     {   if (styleBits)
  436.                             *styleBits = sp[1];
  437.                         GetResInfo(fond, &resID, &resType, resName);
  438.                         return resID;
  439.                     }
  440.                     sp += 3;        /* three elements in the FAT */
  441.                 }
  442.             } while ((fond = XGetNextFOND(fond)) != 0);
  443.     }
  444. NOT_FOUND:
  445.     return 0;
  446. }
  447.  
  448. /*************** font features *************/
  449.  
  450. long GetMenuRunFeatures(MenuHandle menu, gxFont fontID, gxRunFeature feature[])
  451. {
  452.     long i, featureCount, item, count;
  453.  
  454.     count = 0;
  455.     item = 1;
  456.     featureCount = GXCountFontFeatures(fontID);
  457.     for (i = 1; i <= featureCount; i++)
  458.     {    long settingCount, j;
  459.         gxFontFeature featureType;
  460.         gxFontFeatureSetting* settings;
  461.  
  462.         GXGetFontFeature(fontID, i, nil, &settingCount, nil, &featureType);
  463.         settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting));
  464.         GXGetFontFeature(fontID, i, nil, nil, settings, nil);
  465.         for (j = 0; j < settingCount; j++)
  466.         {    short mark;
  467.                     
  468.                     GetItemMark(menu, item, &mark);
  469.                     if (mark)
  470.                     {    if (feature)
  471.                         {    feature[count].featureType = featureType;
  472.                             feature[count].featureSelector = settings[j].setting;
  473.                         }
  474.                         ++count;
  475.                     }
  476.                     ++item;
  477.         }
  478.         DisposePtr((Ptr)settings);
  479.         if (i < featureCount)
  480.             ++item;        /* skip the underline */
  481.     }
  482.     return count;
  483. }
  484.  
  485. static Boolean SearchRunFeatures(long count, const gxRunFeature feature[], gxFontFeature featureType, long featureSetting)
  486. {    
  487.     if (count)
  488.     {    const gxRunFeature *stop = feature + count;
  489.         do {
  490.             if (feature->featureType == featureType && feature->featureSelector == featureSetting)
  491.                 return true;
  492.             ++feature;
  493.         } while (feature < stop);
  494.     }
  495.     return false;
  496. }
  497.  
  498. void SetMenuRunFeatures(MenuHandle menu, gxFont fontID, long count, const gxRunFeature feature[])
  499. {
  500.     long i, featureCount, item;
  501.  
  502.     item = 1;
  503.     featureCount = GXCountFontFeatures(fontID);
  504.     for (i = 1; i <= featureCount; i++)
  505.     {    long settingCount, j;
  506.         gxFontFeature featureType;
  507.         gxFontFeatureSetting* settings;
  508.  
  509.         GXGetFontFeature(fontID, i, nil, &settingCount, nil, &featureType);
  510.         settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting));
  511.         GXGetFontFeature(fontID, i, nil, nil, settings, nil);
  512.         for (j = 0; j < settingCount; j++)
  513.         {    CheckItem(menu, item, SearchRunFeatures(count, feature, featureType, settings[j].setting));
  514.                     ++item;
  515.         }
  516.         DisposePtr((Ptr)settings);
  517.         if (i < featureCount)
  518.             ++item;        /* skip the underline */
  519.     }
  520. }
  521.  
  522. static gxRunFeature* CopyDefaultFeatures(gxFont fontID, long* featureCount)
  523. {
  524.     long count;
  525.     gxRunFeature* feature = nil;
  526.  
  527.     if (count = GetDefaultFontFeatures(fontID, nil))
  528.         if (feature = (gxRunFeature*)NewPtr(count * sizeof(gxRunFeature)))
  529.             GetDefaultFontFeatures(fontID, feature);
  530.         else
  531.             count = 0;
  532.     if (featureCount)
  533.         *featureCount = count;
  534.     return feature;
  535. }
  536.  
  537. void FontFeatureMenu(MenuHandle menu, gxFont fontID)
  538. {
  539.     long i, featureCount;
  540.     Str255 name;
  541.  
  542.     DeleteMenuItems(menu);
  543.     featureCount = GXCountFontFeatures(fontID);
  544.     for (i = 1; i <= featureCount; i++)
  545.     {    long settingCount, j;
  546.         gxFontFeatureSetting* settings;
  547.  
  548.         GXGetFontFeature(fontID, i, nil, &settingCount, nil, nil);
  549.         settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting));
  550.         GXGetFontFeature(fontID, i, nil, nil, settings, nil);
  551.         for (j = 0; j < settingCount; j++)
  552.         {    FindFontPName(fontID, settings[j].nameID, name);
  553.                     AppendMenu(menu, name);
  554.         }
  555.         DisposePtr((Ptr)settings);
  556.         if (i < featureCount)
  557.             AppendMenu(menu, "\p(-");
  558.     }
  559. }
  560.  
  561. void ToggleFeatureMenuItem(MenuHandle menuH, gxFont fontID, long item)
  562. {
  563.     long i, currItem, featureCount;
  564.  
  565.     featureCount = GXCountFontFeatures(fontID);
  566.     currItem = 1;
  567.     for (i = 1; i <= featureCount; i++)
  568.     {    long settingCount;
  569.         gxFontFeatureFlag flag;
  570.  
  571.         GXGetFontFeature(fontID, i, &flag, &settingCount, nil, nil);
  572.         if (item < currItem + settingCount)
  573.         {    short mark;
  574.         
  575.             GetItemMark(menuH, item, &mark);
  576.             if (flag & gxMutuallyExclusiveFeature)
  577.             {    if (mark == noMark)
  578.                     for (i = currItem; i < currItem + settingCount; i++)
  579.                         CheckItem(menuH, i, i == item);
  580.             }
  581.             else
  582.                 CheckItem(menuH, item, mark == noMark);
  583.             break;
  584.         }
  585.         currItem += settingCount + 1;        /* +1 to skip the dashed divider */
  586.     }
  587. }
  588.  
  589. void ToggleFeatureMenuFeature(MenuHandle menuH, gxFont fontID, gxRunFeature feature)
  590. {
  591.     int    currItem = 1;
  592.     long    i, j, featureCount = GXCountFontFeatures(fontID);
  593.  
  594.     for (i = 1; i <= featureCount; i++)
  595.     {    long                settingCount;
  596.         gxFontFeatureFlag    flag;
  597.         gxFontFeature        featureType;
  598.  
  599.         GXGetFontFeature(fontID, i, &flag, &settingCount, nil, &featureType);
  600.         if (feature.featureType == featureType)
  601.         {    gxFontFeatureSetting* settings;
  602.         
  603.             if (settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting)))
  604.             {    GXGetFontFeature(fontID, i, nil, nil, settings, nil);
  605.                 for (j = 0; j < settingCount; j++)
  606.                     if (settings[j].setting == feature.featureSelector)
  607.                     {    short mark, item = currItem + j;
  608.                     
  609.                         GetItemMark(menuH, item, &mark);
  610.                         if (flag & gxMutuallyExclusiveFeature)
  611.                         {    if (mark == noMark)
  612.                                 for (j = currItem; j < currItem + settingCount; j++)
  613.                                     CheckItem(menuH, j, j == item);
  614.                         }
  615.                         else
  616.                             CheckItem(menuH, item, mark == noMark);
  617.                         break;
  618.                     }
  619.                 DisposePtr((Ptr)settings);
  620.             }
  621.             break;
  622.         }
  623.         currItem += settingCount + 1;        /* +1 to skip the dashed divider */
  624.     }
  625. }
  626.  
  627. void StyleFeatureMenu(MenuHandle menuH, const gxStyle style)
  628. {
  629.     gxFont fontID = GXGetStyleFont(style);
  630.     long featureCount = GXGetStyleRunFeatures(style, nil);
  631.  
  632.     FontFeatureMenu(menuH, fontID);
  633.     if (featureCount)
  634.     {    gxRunFeature* feature = (gxRunFeature*)NewPtr(featureCount * sizeof(gxRunFeature));
  635.  
  636.         if (feature)
  637.         {    GXGetStyleRunFeatures(style, feature);
  638.             SetMenuRunFeatures(menuH, fontID, featureCount, feature);
  639.             DisposePtr((Ptr)feature);
  640.         }
  641.     }
  642. }
  643.  
  644. typedef struct {
  645.     unsigned long    defaultFlags;            /* The default sub-feature flags for this chain. */
  646.     unsigned long    chainLength;            /* The length of the chain in bytes, including this header. */
  647.     unsigned short    nFeatureEntries;        /* The number of entries in the chain's feature table. */
  648.     unsigned short    nSubtables;            /* The number of subtables in the chain. */
  649. } ChainHeader;
  650.  
  651. typedef struct {
  652.     Fixed        version;                /* Version number of the glyph metamorphosis table (0x00010000 for the initial version. */
  653.     unsigned long    nChains;                /* Number of metamorphosis chains which follow. */
  654. } MortHeader;
  655.  
  656. typedef struct {
  657.     unsigned short    featureType;
  658.     unsigned short    featureSetting;
  659.     unsigned long    enableFlags;            /* Flags for sub-features this feature and setting enables. */
  660.     unsigned long    disableFlags;            /* Complement of flags for sub-features this feature and setting disables. */
  661. } FeatureTableEntry;
  662.  
  663. /*
  664.  *    GetFontDefaultFeatures returns a list of features and settings that are on by default in the specified font.
  665.  *    This routine will be added to the next GX Font Manager, as the format for the 'mort' table may change in the future.
  666. */
  667. long GetDefaultFontFeatures(gxFont fontID, gxRunFeature features[])
  668. {
  669.     #define kGXVersionWhenDefaultFeaturesWasAdded    0x00010100
  670.     long mortIndex, defaultFeatureCount;
  671.     long response;
  672.  
  673.     Gestalt(gestaltGraphicsVersion, &response);
  674.     if (response >= kGXVersionWhenDefaultFeaturesWasAdded)
  675.         return GXGetFontDefaultFeatures(fontID, features);
  676.  
  677.     defaultFeatureCount = 0;
  678.     if (GXFindFontTable(fontID, 'mort', nil, &mortIndex))
  679.     {    MortHeader*    mortHead;
  680.         ChainHeader*    chainHead;
  681.         long            size, chainCount;
  682.         
  683.         size = GXGetFontTable(fontID, mortIndex, nil, nil);
  684.         mortHead = (MortHeader*)NewPtr(size);
  685.         if (mortHead == nil)
  686.             return 0;
  687.  
  688.         defaultFeatureCount = 1;
  689.         if (features)
  690.         {    features->featureType = allTypographicFeaturesType;
  691.             features->featureSelector = allTypeFeaturesOnSelector;
  692.             ++features;
  693.         }
  694.         GXGetFontTable(fontID, mortIndex, mortHead, nil);
  695.         chainCount = mortHead->nChains;
  696.  
  697.         chainHead = (ChainHeader*)(mortHead + 1);        
  698.         while (chainCount--)
  699.         {    if (chainHead->nFeatureEntries)
  700.             {    unsigned long        defaultFlags;
  701.                 FeatureTableEntry*    featureEntry;
  702.                 int                featureCount;
  703.                 
  704.                 defaultFlags = chainHead->defaultFlags;
  705.                 featureEntry = (FeatureTableEntry*)(chainHead + 1);
  706.                 featureCount = chainHead->nFeatureEntries;
  707.                 
  708.                 while (featureCount--)
  709.                 {    if (featureEntry->enableFlags & defaultFlags)
  710.                     {    if (features)
  711.                         {    features->featureType = featureEntry->featureType;
  712.                             features->featureSelector = featureEntry->featureSetting;
  713.                             ++features;
  714.                         }
  715.                         ++defaultFeatureCount;
  716.                     }
  717.                     ++featureEntry;
  718.                 }
  719.             }
  720.             chainHead = (ChainHeader*)((char*)chainHead + chainHead->chainLength);
  721.         }
  722.         DisposePtr((Ptr)mortHead);
  723.     }
  724.     return defaultFeatureCount;    
  725. }
  726.  
  727. void SetShapeDefaultFeatures(gxShape dst, gxFont fontID)
  728. {
  729.     long featureCount;
  730.     gxRunFeature* feature;
  731.  
  732.     feature = CopyDefaultFeatures(fontID, &featureCount);
  733.     GXIgnoreGraphicsNotice(attributes_already_set);
  734.     GXSetShapeRunFeatures(dst, featureCount, feature);
  735.     GXPopGraphicsNotice();
  736.     if (feature)
  737.         DisposePtr((Ptr)feature);
  738. }
  739.  
  740. void SetStyleDefaultFeatures(gxStyle dst, gxFont fontID)
  741. {
  742.     long featureCount;
  743.     gxRunFeature* feature;
  744.  
  745.     feature = CopyDefaultFeatures(fontID, &featureCount);
  746.     GXIgnoreGraphicsNotice(attributes_already_set);
  747.     GXSetStyleRunFeatures(dst, featureCount, feature);
  748.     GXPopGraphicsNotice();
  749.     if (feature)
  750.         DisposePtr((Ptr)feature);
  751. }
  752.  
  753.